/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package flight.server;

import flight.model.Flight;
import flight.model.FlightDataSource;
import flight.model.FlightList;
import flight.service.FlightService;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.Timer;
import middleware.Callback;
/**
 *
 * @author tam
 */
public class FlightServiceImpl implements FlightService {
    FlightDataSource ds;
    HashMap<Integer,List<Callback>> seatMonitor;
    List<Timer> timers;
    public FlightServiceImpl(FlightDataSource d){
        seatMonitor = new HashMap<Integer,List<Callback>>();
        ds = d;
    }
    public FlightList getIdsBySourceAndDest(String s, String d) {
        System.out.println("SERVER: get Ids from " + s + " to " + d);
        List<Flight> flights = ds.getAll();
        List<Flight> res = new ArrayList<Flight>();
        for(Flight f:flights){
            if(f.source.equalsIgnoreCase(s) && f.destination.equalsIgnoreCase(d))
                res.add(f);
        }
        System.out.println("result " + res.size() + " flights");
        return new FlightList(res);
    }

    public Flight getFlightById(int id) {
        return ds.getById(id);
    }

    public String reserveSeats(int id, int noOfSeats) {
        Flight f = ds.getById(id);
        if(f == null)
            return "Error: flight no."+id+" doesn't exist";
        else{
            
            if(f.noOfSeats >= noOfSeats){
                int inital=f.noOfSeats;
                f.noOfSeats -= noOfSeats;
                System.out.println("Update number of seat number of flight id="+id+", initial value is "+inital+", new value is "+f.noOfSeats);
                List<Callback> lcb = seatMonitor.get(id);
                if(lcb!=null && lcb.size()>0){
                    synchronized(lcb){
                        for(Callback c : lcb){
                            System.out.println("Inform seat update to " + c.getIp());
                            c.informSeatUpdate(f.noOfSeats);
                        }
                    }
                }
                return "Successfully reserved " + noOfSeats + " seats - " + f.noOfSeats + " seats left";
            }
            else{
                return "Error: less than " + noOfSeats + " seats available";
            }

       }

    }

    public Object invoke(String methodName, Object[] parameters) {
        if(methodName.equalsIgnoreCase("getIdsBySourceAndDest")){
            return getIdsBySourceAndDest((String)parameters[0],(String)parameters[1]);
        }
        else if(methodName.equalsIgnoreCase("getFlightById")){
            return getFlightById((Integer)parameters[0]);
        }
        else if(methodName.equalsIgnoreCase("reserveSeats")){
            return reserveSeats((Integer)parameters[0],(Integer)parameters[1]);
        }
        else if(methodName.equalsIgnoreCase("registerCallbackFlightClient")){
            System.out.println("Invoke register callback");
            return registerCallbackFlightClient((Integer)parameters[0],(Integer)parameters[1],(Callback)parameters[2]);            
        }
        else if(methodName.equalsIgnoreCase("getFlightsOnDate")){
            return getFlightsOnDate((String)parameters[0]);
        }
        else if(methodName.equalsIgnoreCase("getCheapest")){
            return getCheapest();
        }
        else if(methodName.equalsIgnoreCase("discountPrice")){
            return discountPrice((Integer)parameters[0],(Float)parameters[1]);
        }
        else
            return null;
    }

    public String registerCallbackFlightClient(int flightId, int interval, Callback obj) {
        System.out.println("SERVER: Register callback");
        List<Callback> lcb = seatMonitor.get(flightId);
        if(lcb == null){
            lcb = new ArrayList<Callback>();
            seatMonitor.put(flightId, lcb);
        }
        if(obj==null)
            return "Error callback object";
        synchronized(lcb){
            lcb.add(obj);
        }
        //start timer to remove callback
        Timer timer  = new Timer(); //NOTE: local object -> can? 
        timer.schedule(new DeregisterCallbackTask(flightId, obj.getIp(),lcb), interval);
        return "Register callback successfully";


        //Timer t = new Timer()
    }

    public FlightList getFlightsOnDate(String date) {
        try {
            List<Flight> flights = ds.getAll();
            List<Flight> res = new ArrayList<Flight>();
            Calendar cal = new GregorianCalendar();
            DateFormat df = new SimpleDateFormat("dd/MM/yyyy");
            Date queryDate = df.parse(date);
            Calendar cal2 = new GregorianCalendar();
            cal2.setTime(queryDate);


            for (Flight f : flights) {
                Date flightDate = new Date(f.time);
                cal.setTime(flightDate);
                if(cal.get(Calendar.DATE) == cal2.get(Calendar.DATE) && cal.get(Calendar.MONTH) == cal2.get(Calendar.MONTH) && cal.get(Calendar.YEAR) == cal2.get(Calendar.YEAR))
                    res.add(f);
            }
            return new FlightList(res);
        } catch (ParseException ex) {
            Logger.getLogger(FlightServiceImpl.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }

    public Flight getCheapest() {

        List<Flight> flights = ds.getAll();
        //float minFare = flights.get(0).airfare;
        Flight res = flights.get(0);
        for(Flight f:flights){
            if(f.airfare < res.airfare){
                res = f;
            }
        }
        return res;
    }

    public String discountPrice(int id, float percentage) {
        Flight f = ds.getById(id);
        if(f == null)
            return "Invalid Flight Id #"+id;
        if(percentage > 100 || percentage <0)
            return "Invalid discount percentage";
        f.airfare = f.airfare*(100-percentage)/100;
        return "Successfully discount airfare - new airfare " + f.airfare;
    }

}
